<!--
 * @Author: aster lipian1004@163.com
 * @Date: 2025-02-20 17:09:28
 * @FilePath: \aster-flowable-uniapp\src\components\form\render\dept-picker.vue
 * @Description: 部门
 * Copyright (c) 2025 by Aster, All Rights Reserved.
-->
<template>
  <van-field
    v-if="!_hidden"
    :name="formItemProp"
    :readonly="_readonly"
    :required="_required"
    :rules="_rules"
    :input-align="FieldInputAlignEnum.RIGHT"
    :error-message-align="FieldInputAlignEnum.RIGHT"
    :label-width="showLabel ? '' : '5rpx'"
    :placeholder="_placeholder"
    is-link
    @click="handleOpen"
  >
    <template #label>
      <text v-if="showLabel">{{ formItem.title }}</text>
    </template>
    <template #extra>
      <view class="field-right" v-if="isNotEmpty(_name_value)">
        <van-tag
          type="primary"
          class="!p-8rpx m-5rpx"
          v-for="(item, index) in _name_value"
          :key="index"
        >
          {{ item }}
        </van-tag>
      </view>
    </template>
  </van-field>

  <van-popup v-model:show="showPicker" round position="bottom" class="user-data-container">
    <!-- 导航 -->
    <view class="card">
      <view class="nav-container">
        <span
          class="nav-name"
          v-for="(navItem, index) in navData"
          :key="index"
          @click="pop(navItem, index)"
        >
          <span class="interval" v-if="index !== 0">|</span>
          <i v-if="navItem.icon" :class="navItem.icon" style="padding: 0 8rpx" />
          <span v-else style="padding: 0 8rpx">{{ navItem.name }}</span>
        </span>
      </view>
    </view>
    <!-- 多选部门 -->
    <view class="card">
      <van-checkbox-group v-model="_id_value">
        <!-- 限制可选择部门时 -->
        <template v-if="_canselected.ids && _canselected.ids.length > 0">
          <van-cell
            size="large"
            v-for="(deptItem, index) in deptData"
            :key="index"
            @click="clickItem(deptItem, index)"
          >
            <template #title>
              <span>
                {{ deptItem.name }}
              </span>
            </template>
            <template #right-icon>
              <van-checkbox
                :name="deptItem.id"
                :ref="(el) => (checkboxRefs[index] = el)"
                @click.stop="clickItem(deptItem, index)"
              />
            </template>
          </van-cell>
        </template>
        <!-- 不限制可选择部门时  -->
        <template v-else>
          <view class="dept-container" v-for="(deptItem, index) in deptData" :key="index">
            <van-cell
              class="dept-container__cell"
              size="large"
              :title="deptItem.name"
              @click="clickItem(deptItem, index)"
            >
              <template #icon>
                <van-checkbox
                  :name="deptItem.id"
                  :ref="(el) => (checkboxRefs[index] = el)"
                  class="pr-20rpx"
                  @click.stop="clickItem(deptItem, index)"
                />
              </template>
            </van-cell>
            <view class="cell-icon" @click="nextGrade(deptItem)">
              <van-icon name="list-switch" class="suffix-icon" />
              <span class="suffix-text">下级</span>
            </view>
          </view>
          <view class="dept-display" v-if="isNotEmpty(_value)">
            <view class="dept-display__title">已选择部门</view>
            <van-cell v-for="(item, index) in _value" :title="item.name" :key="index">
              <template #right-icon>
                <i
                  class="iconfont icon-shanchu !text-lg text-red-600"
                  @click="deleteItem(item.id)"
                />
              </template>
            </van-cell>
          </view>
        </template>
      </van-checkbox-group>
      <van-empty description="暂无部门" v-if="deptData.length < 1" />

      <aster-tabbar
        ref="userTabbarRef"
        :customStyle="{ borderTopLeftRadius: '10px', borderTopRightRadius: '10px' }"
      >
        <van-button type="primary" block @click="onConfirm">确定选择</van-button>
      </aster-tabbar>
    </view>
  </van-popup>
</template>
<script setup lang="ts">
  import { evaluateFormula } from '@/utils/workflow';
  import { computed, PropType, ref, watch } from 'vue';
  import { isNotEmpty, isEmpty, isArray } from '@/utils/is';
  import { FormPermissionEnum } from '@/enums/workFlowEnum';
  import { FieldInputAlignEnum } from '@/enums/formEnum';
  import { onLoad } from '@dcloudio/uni-app';
  import AsterTabbar from '@/components/common/aster-tabbar.vue';
  import { deptAllApi } from '@/api/sys/dept';
  import { Toast } from '@/utils/uniapi/prompt';
  import { instanceInfoByCustomParamsApi } from '@/api/workflow/process';

  const emit = defineEmits(['update:value']);
  const props = defineProps({
    value: { type: Array as PropType<string[]>, default: () => [] },
    mode: {
      type: String as PropType<'design' | 'form' | 'search' | 'table' | 'print'>,
      default: 'design',
    },
    formData: { type: Object as PropType<WorkForm.FormDataModel>, default: {} },
    formItem: { type: Object as PropType<WorkComponent.ComponentConfig>, default: {} },
    tableId: { type: String, default: '' },
    tableIndex: { type: Number, default: 0 },
    showLabel: { type: Boolean, default: true },
  });

  const checkboxRefs = ref<any[]>([]);
  // 显示弹出层
  const showPicker = ref(false);
  // 所有用户信息
  const deptList = ref<Dept.DeptInfo[]>([]);
  // 导航数据
  const navData = ref<User.UserDeptModel[]>([]);
  // 部门数据
  const deptData = ref<User.UserDeptModel[]>([]);
  // 是否多选, 默认单选
  const multiple = ref<boolean>(false);
  // value
  const _value = ref<User.UserDeptModel[]>([]);
  // checkbox value
  const _id_value = ref<string[]>([]);
  // 用于展示的 value
  const _name_value = ref<string[]>([]);

  // 打开签名弹出层
  const handleOpen = () => {
    if (!_readonly.value) {
      showPicker.value = true;
    }
  };

  /**
   * @description: 点击导航
   * @param deptItem 部门对象
   * @param index 导航索引
   */
  const pop = (dept: User.UserDeptModel, index: number) => {
    navData.value = navData.value.slice(0, index + 1);
    getUserDeptData(dept.id);
  };

  /**
   * @description: 下一级
   * @param deptItem 部门对象
   */
  const nextGrade = (dept: User.UserDeptModel) => {
    navData.value.push(dept);
    getUserDeptData(dept.id);
  };

  /**
   * @description: 点击部门
   * @param userItem 部门对象
   */
  const clickItem = (dept: User.UserDeptModel, index: number) => {
    checkboxRefs.value[index].toggle();
    // 如果单选
    if (!multiple.value) {
      if (_id_value.value.length > 0) {
        _id_value.value = [dept.id];
        _value.value = [dept];
      } else {
        _value.value = [];
      }
    } else {
      // 如果存在
      if (_id_value.value.indexOf(dept.id) !== -1) {
        _value.value.push(dept);
      } else {
        for (let i = 0; i < _value.value.length; i++) {
          if (_value.value[i].id === dept.id) {
            _value.value.splice(i, 1);
          }
        }
      }
    }
  };

  /**
   * @description: 删除已选部门
   */
  const deleteItem = (id: string) => {
    for (let i = 0; i < _value.value.length; i++) {
      if (_value.value[i].id === id) {
        _value.value.splice(i, 1);
      }
    }
    if (_value.value.length > 0) {
      _id_value.value = _value.value.map((item) => {
        return item.id;
      });
      _name_value.value = _value.value.map((item) => {
        return item.name;
      });
    } else {
      _id_value.value = [];
      _name_value.value = [];
    }
  };

  /**
   * @description: 限制选中人员
   */
  const _canselected = computed(() => {
    return props.formItem.props?.canselected;
  });

  /**
   * @description: 获取用户部门数据
   */
  const getUserDeptData = async (deptId: string) => {
    deptData.value = [];
    const limitDeptIds = _canselected.value?.ids;
    if (limitDeptIds && limitDeptIds.length > 0) {
      deptData.value = deptList.value
        .filter((item: Dept.DeptInfo) => {
          return limitDeptIds.some((id: string) => {
            return item.id === id;
          });
        })
        .map((item: Dept.DeptInfo) => {
          return { id: item.id ? item.id : '', name: item.orgName, type: 'dept' };
        });
    } else {
      deptData.value = deptList.value
        .filter((item: Dept.DeptInfo) => {
          return item.pid === deptId;
        })
        .map((item: Dept.DeptInfo) => {
          return { id: item.id ? item.id : '', name: item.orgName, type: 'dept' };
        });
    }
  };

  /**
   * @description: 确认选择
   */
  const onConfirm = () => {
    if (_required.value && isEmpty(_value.value)) {
      Toast('请至少选择一个' + props.formItem.title);
      return false;
    }
    _name_value.value = [];
    for (let i = 0; i < _value.value.length; i++) {
      _name_value.value.push(_value.value[i].name);
    }
    const deptIds = isNotEmpty(_value.value) ? _value.value.map((item) => item.id) : [];
    emit('update:value', deptIds);
    showPicker.value = false;
  };

  // 键
  const formItemProp = computed(() => {
    if (isNotEmpty(props.tableId)) {
      return props.tableId + '.' + props.tableIndex + '.' + props.formItem.id;
    } else {
      return props.formItem.id;
    }
  });

  /**
   * @description: 提示词
   */
  const _placeholder = computed(() => {
    if (_readonly.value) {
      return '';
    }
    return isNotEmpty(_value.value) ? '' : props.formItem.props.placeholder;
  });

  /**
   * @description: 是否必填, true-必填
   */
  const _required = computed(() => {
    return props.formItem.props.required;
  });

  /**
   * @description: 是否只读, true-只读
   */
  const _readonly = computed(() => {
    let r = props.formItem.props.readonly;
    if (props.formItem.operation && props.formItem.operation.length > 0) {
      r = r || props.formItem.operation[0] == FormPermissionEnum.READONLY;
    }
    return r;
  });

  /**
   * @description: 校验规则
   */
  const _rules = computed(() => {
    const isRequired = _required.value;
    if (props.mode != 'form') {
      return [];
    }
    return isRequired ? [{ required: true, message: `请输入${props.formItem.title}` }] : [];
  });

  /**
   * @description: 是否隐藏, true-隐藏
   */
  const _hidden = computed(() => {
    let r = false;
    // 解析隐藏条件公式
    if (props.formItem.props.hidden) {
      let expression = props.formItem.props.hidden;
      // 如果是子表中的控件，则需要用到下标
      if (isNotEmpty(props.tableId)) {
        expression = expression.replaceAll('?', props.tableIndex);
      }
      r = evaluateFormula(expression, props.formData);
    }
    // 判断流程节点下该控件是否隐藏
    if (props.formItem.operation && props.formItem.operation.length > 0) {
      r = r || props.formItem.operation[0] == FormPermissionEnum.HIDDEN;
    }
    return r;
  });

  /**
   * @description: 监听表单数据变化
   */
  const _formData = computed(() => {
    return JSON.parse(JSON.stringify(props.formData));
  });

  /**
   * @description: 监听表单数据变化
   */
  watch(
    () => _formData.value,
    async (nval, oval) => {
      if (nval && props.formItem && props.formItem.props.default) {
        // 默认值-数据联动
        const defaultConfig = props.formItem.props.default;
        if (
          defaultConfig.type === 'linkage' &&
          isNotEmpty(defaultConfig.linkage.formCode) &&
          isNotEmpty(defaultConfig.linkage.conditions) &&
          isNotEmpty(defaultConfig.linkage.dataFill)
        ) {
          const conditionStr = JSON.stringify(defaultConfig.linkage.conditions);
          Object.keys(nval).forEach(async (key) => {
            // 判断联动条件中的当前表单的字段的值是否有变动，如有则重新赋值
            if (conditionStr.indexOf(key) != -1 && oval != undefined && nval[key] != oval[key]) {
              const targetCode = defaultConfig.linkage.formCode[1];
              let targetParams = {};
              defaultConfig.linkage.conditions.forEach((item) => {
                if (isNotEmpty(item.currentFieldId) && isNotEmpty(item.associatedFieldId)) {
                  targetParams[item.associatedFieldId] = nval[item.currentFieldId];
                }
              });
              // 根据条件查询目标表单的流程实例
              await instanceInfoByCustomParamsApi(targetCode, targetParams).then(({ data }) => {
                if (data) {
                  const dataFill = defaultConfig.linkage.dataFill;
                  // 如果目标表单中存在该填充字段，则赋值
                  if (data.hasOwnProperty(dataFill) && isNotEmpty(data[dataFill])) {
                    const associatedValue = data[dataFill];
                    if (isArray(associatedValue)) {
                      _value.value = associatedValue;
                    } else {
                      _value.value =
                        associatedValue.indexOf('[') != -1 ? JSON.parse(associatedValue) : [];
                    }
                  } else {
                    _value.value = props.formItem.value;
                  }
                } else {
                  // 流程实例不存在则重置为空
                  _value.value = props.formItem.value;
                }
              });
            }
          });
        }
      }
    },
    { immediate: true, deep: true },
  );

  /**
   * @description: 初始化数据
   * @return {*}
   */
  const init = () => {
    if (isNotEmpty(props.value) && isNotEmpty(deptList.value)) {
      _id_value.value = JSON.parse(JSON.stringify(props.value));
      _value.value = deptList.value
        .filter((f) => {
          return f.id && props.value.indexOf(f.id) !== -1;
        })
        .map((m) => {
          return { id: m.id ? m.id : '', name: m.orgName, type: 'dept' };
        });
      _name_value.value = _value.value.map((m) => {
        return m.name;
      });
    }
  };

  /**
   * @description: 获取所有部门信息
   */
  const getAllDeptInfo = async () => {
    await deptAllApi().then(({ data }) => {
      deptList.value = data;
      init();
    });
  };

  onLoad(async () => {
    multiple.value = props.formItem.props.multiple;
    await getAllDeptInfo();
    navData.value.push({ id: '0', name: '全部', type: 'dept', icon: 'iconfont icon-SmartHome' });
    await getUserDeptData('0');
  });

  defineExpose({ _hidden });
</script>
<style scoped lang="scss">
  .user-data-container {
    background-color: #f8f8f8;
    height: 60%;
  }
  .card {
    width: 100%;
    margin-top: 20rpx;
  }

  .cell-icon {
    height: 100%;
    line-height: 1;
  }

  .suffix-icon {
    color: #1989fa;
    scale: (1.1);
  }

  .suffix-text {
    color: #1989fa;
  }

  .nav-container {
    height: 35px;
    padding-left: 10px;
    font-size: 18px;
    display: flex;
    align-items: center;
  }

  .interval {
    padding: 0px 3px;
    color: #959292;
  }

  .nav-name {
    color: #1989fa;
  }

  .dept-container {
    display: flex;
    align-items: center;
    padding: 0 10rpx;
    background-color: #fff;

    &__cell {
      flex: 1;
    }
  }

  .dept-name {
    color: #1989fa !important;
  }

  .dept-display {
    &__title {
      padding: 30rpx 30rpx;
      color: #1989fa;
    }
  }

  .field-right {
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
  }
</style>
